// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-11-20

package searched

import (
	"fmt"
	"sort"
	"strings"
)

// Span
// 跟踪信息.
type Span struct {
	Address            string  `json:"address"`
	Duration           int64   `json:"duration" label:"跟踪耗时(单位: us)"`
	DurationWith       string  `json:"duration_text"`
	EndTime            int64   `json:"end_time" label:"结束时间"`
	ItemCount          int     `json:"item_count"`
	ItemList           []*Item `json:"items" label:"开始时间"`
	ItemTotal          int     `json:"item_total"`
	ParentSpanId       string  `json:"parent_span_id" label:"上级跟踪ID"`
	ParentSpanPosition int     `json:"parent_span_position" label:"上级跟踪点位"`
	Pid                int     `json:"pid"`
	ServiceName        string  `json:"service_name"`
	ServicePort        int     `json:"service_port"`
	SpanCount          int     `json:"span_count"`
	SpanId             string  `json:"span_id" label:"跟踪ID"`
	SpanList           []*Span `json:"span_list,omitempty" label:"子级跟踪列表"`
	StartTime          int64   `json:"start_time" label:"开始时间"`
	StartTimeMs        string  `json:"start_time_ms" label:"开始时间"`
	TraceId            string  `json:"trace_id" label:"链路ID"`

	notSortedItems []*Item
	notSortedSpan  map[int][]*Span
}

// NewSpan
// 创建跟踪信息.
func NewSpan() *Span {
	return &Span{
		ItemList:       make([]*Item, 0),
		SpanList:       make([]*Span, 0),
		notSortedItems: make([]*Item, 0),
		notSortedSpan:  make(map[int][]*Span),
	}
}

// Add
// 添加日志条目.
func (o *Span) Add(item *Item) {
	o.notSortedItems = append(o.notSortedItems, item)

	if o.Address == "" && len(item.ServiceAddresses) > 0 {
		o.Address = strings.Join(item.ServiceAddresses, ",")
	}

	if o.ServiceName == "" && item.ServiceName != "" {
		o.ServiceName = item.ServiceName
	}

	if o.ServicePort == 0 && item.ServicePort > 0 {
		o.ServicePort = item.ServicePort
	}

	if o.Pid == 0 && item.Pid > 0 {
		o.Pid = item.Pid
	}

	// 链路ID.
	if o.TraceId == "" && item.TraceId != "" {
		o.TraceId = item.TraceId
	}

	// 跟踪ID.
	if o.SpanId == "" && item.SpanId != "" {
		o.SpanId = item.SpanId
	}

	// 上级跟踪.
	if o.ParentSpanId == "" && item.ParentSpanId != "" {
		o.ParentSpanId = item.ParentSpanId
		o.ParentSpanPosition = item.ParentSpanPosition
	}

	// 开始时间.
	if o.StartTime == 0 || o.StartTime > item.TimeMicro {
		o.StartTime = item.TimeMicro
		o.StartTimeMs = item.Time.Format("2006-01-02 15:04:05.999999 Z07")
	}

	// 结束时间.
	if o.EndTime == 0 || o.EndTime < item.TimeMicro {
		o.EndTime = item.TimeMicro
	}

	// 跟踪用时.
	o.Duration = o.EndTime - o.StartTime

	if o.Duration > 1000 {
		o.DurationWith = fmt.Sprintf("%dms", o.Duration/1000)
	} else {
		o.DurationWith = fmt.Sprintf("%dus", o.Duration)
	}
}

// Child
// 构建子级.
func (o *Span) Child(mapper Mapper) {
	for _, span := range mapper {
		if span.ParentSpanId == o.SpanId {
			span.Child(mapper)

			pos := span.ParentSpanPosition
			if _, ok := o.notSortedSpan[pos]; !ok {
				o.notSortedSpan[pos] = make([]*Span, 0)
			}

			o.notSortedSpan[pos] = append(o.notSortedSpan[pos], span)
		}
	}
}

// Sort
// 元素排序.
func (o *Span) Sort() *Span {
	var (
		deletes = make(map[int]int)
		index   = make(map[string]*Item)
		key     string
		keys    = make([]string, 0)
	)

	// 1. 构建中间值.
	for i, item := range o.notSortedItems {
		// 1.1 设置字级.
		if ss, ok := o.notSortedSpan[item.SpanPosition]; ok {
			if _, has := deletes[item.SpanPosition]; !has {
				item.Add(ss)
				deletes[item.SpanPosition] = item.SpanPosition
			}
		}

		// 1.2 子级排序.
		item.Sort()

		// 1.3 中间数据.
		key = fmt.Sprintf(`%d-%04d-%04d`, item.TimeMicro, item.SpanPosition, i)
		keys = append(keys, key)
		index[key] = item
	}

	// 2. 中间排序.
	sort.Strings(keys)

	// 3. 按顺序添加.
	for _, key = range keys {
		if span, ok := index[key]; ok {
			o.ItemList = append(o.ItemList, span)
		}
	}

	// 4. 断裂跟踪.
	o.SortSpanList(deletes)

	// 5. 清理数据.
	o.notSortedItems = nil
	o.notSortedSpan = nil
	return o
}

func (o *Span) SortSpanList(deletes map[int]int) {
	var (
		index = make(map[string]*Span)
		key   string
		keys  = make([]string, 0)
	)

	for pos, spans := range o.notSortedSpan {
		if _, ok := deletes[pos]; ok {
			continue
		}

		for i, span := range spans {
			span.Sort()
			key = fmt.Sprintf(`%d-%04d`, span.StartTime, i)
			keys = append(keys, key)
			index[key] = span
		}
	}

	sort.Strings(keys)

	for _, key = range keys {
		if span, ok := index[key]; ok {
			o.SpanList = append(o.SpanList, span)
		}
	}
}

func (o *Span) Update() {
	if o.ItemCount = len(o.ItemList); o.ItemCount > 0 {
		o.ItemTotal = o.ItemCount

		for _, item := range o.ItemList {
			item.Update()
			o.ItemTotal += item.ItemTotal
		}
	}
}
